package com.gooluke.gateway.filter;

import com.gooluke.gateway.config.AuthWhitelistConfig;
import com.gooluke.gateway.util.JwtUtils;
import com.gooluke.redis.uitl.RedisUtil;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

@Component
public class JwtAuthFilter implements GlobalFilter, Ordered {

    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String BEARER_TYPE = "Bearer ";

    @Autowired
    private AuthWhitelistConfig whitelistConfig;
    @Autowired
    private JwtUtils jwtUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Value("${interface.test.enable:false}")
    private boolean isTest;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //接口测试中，不需要验证
        if (isTest) {
            return chain.filter(exchange);
        }

        // 检查白名单接口
        String path = exchange.getRequest().getPath().toString();
        if (isWhitelisted(path)) {
            return chain.filter(exchange);
        }
        String token = exchange.getRequest().getHeaders().getFirst(AUTHORIZATION_HEADER);

        // 1. 检查Token是否存在
        if (token == null || !token.startsWith(BEARER_TYPE)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        String jwt = token.replace(BEARER_TYPE, "");

        // 2. 检查Token是否在黑名单（已注销）
        if (Boolean.TRUE.equals(redisUtil.hasKey("jwt:blacklist:" + jwt))) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        // 3. 校验Token有效性
        try {
            String userId = jwtUtil.getUsernameFromToken(jwt);
            exchange.getAttributes().put("userId", userId);
            return chain.filter(exchange);
        } catch (ExpiredJwtException expiredJwtException) {
            // 设置响应状态码
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            // 设置响应头
            exchange.getResponse().getHeaders().setContentType(MediaType.TEXT_PLAIN);
            // 构建错误响应体
            String errorResponse = "token expired";
            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(errorResponse.getBytes(StandardCharsets.UTF_8));
            // 返回完整响应
            return exchange.getResponse().writeWith(Mono.just(buffer));
        } catch (Exception e) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            exchange.getResponse().getHeaders().setContentType(MediaType.TEXT_PLAIN);
            // 其他异常也可以添加错误信息
            String errorResponse = "invalid token";
            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(errorResponse.getBytes(StandardCharsets.UTF_8));
            return exchange.getResponse().writeWith(Mono.just(buffer));
        }
    }


    private boolean isWhitelisted(String path) {
        return whitelistConfig
                .getWhitelist()
                .stream()
                .anyMatch(whitelistPath -> path.matches(whitelistPath.replace("**", ".*")));
    }

    @Override
    public int getOrder() {
        return -100; // 高优先级
    }
}